home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 24 / Amiga Format AFCD24 (Feb 1998, Issue 108).iso / -in_the_mag- / emulation / uae / uae-0.4.3 / newcpu.c < prev    next >
C/C++ Source or Header  |  1998-01-20  |  14KB  |  657 lines

  1.  /* 
  2.   * UAE - The Un*x Amiga Emulator
  3.   * 
  4.   * MC68000 emulation
  5.   *
  6.   * (c) 1995 Bernd Schmidt
  7.   */
  8. #include <stdio.h>
  9. #include <assert.h>
  10. #include <string.h>
  11. #include <stdlib.h>
  12.  
  13. #include "config.h"
  14. #include "amiga.h"
  15. #include "options.h"
  16. #include "events.h"
  17. #include "memory.h"
  18. #include "custom.h"
  19. #include "newcpu.h"
  20. #include "ersatz.h"
  21. #include "readcpu.h"
  22.  
  23. cpuop_func *cpufunctbl[65536];
  24.  
  25. #undef COUNT_INSTRS
  26.  
  27. #ifdef COUNT_INSTRS
  28. static unsigned long int instrcount[65536];
  29. static UWORD opcodenums[65536];
  30.  
  31. int compfn(const void *el1, const void *el2)
  32. {
  33.     return instrcount[*(const UWORD *)el1] < instrcount[*(const UWORD *)el2];
  34. }
  35.  
  36. void dump_counts(void)
  37. {
  38.     FILE *f = fopen("insncount", "w");
  39.     unsigned long int total = 0;
  40.     int i;
  41.     
  42.     for(i=0; i < 65536; i++) {
  43.     opcodenums[i] = i;
  44.         total += instrcount[i];
  45.     }
  46.     qsort(opcodenums, 65536, sizeof(UWORD), compfn);
  47.     
  48.     fprintf(f, "Total: %ld\n", total);
  49.     for(i=0; i < 65536; i++) {
  50.     unsigned long int cnt = instrcount[opcodenums[i]];
  51.     if (!cnt)
  52.         break;
  53.     fprintf(f, "%04x: %ld\n", opcodenums[i], cnt);
  54.     }
  55.     fclose(f);
  56. }
  57. #endif
  58.  
  59. bool broken_in;
  60.  
  61. #ifdef DUALCPU
  62. bool allowmem;
  63. bool customacc;
  64. #endif
  65.  
  66. static cpuop_func *find_func_for (UWORD opcode)
  67. {
  68.     int i = 0;
  69.     
  70.     if (cpufunctbl[opcode] != op_illg)
  71.     return cpufunctbl[opcode];
  72.  
  73.     for (;;i++) {
  74.     if (smallcputbl[i].opcode == opcode)
  75.         return smallcputbl[i].handler;
  76.     }
  77. }
  78.  
  79. void init_m68k (void)
  80. {
  81.     long int opcode;
  82.     
  83. #ifdef COUNT_INSTRS
  84.     int i;
  85.     for(i=0;i<65536;i++) {
  86.     instrcount[i] = 0;
  87.     }
  88. #endif
  89.     read_table68k ();
  90.     do_merges ();
  91.     printf("Building CPU table...\n");
  92.     for (opcode = 0; opcode < 65536; opcode++)
  93.     cpufunctbl[opcode] = op_illg;
  94.     for (opcode = 0; opcode < 65536; opcode++) {
  95.     if (table68k[opcode].mnemo == i_ILLG)
  96.         continue;
  97.     
  98.     if (table68k[opcode].handler == -1)
  99.         cpufunctbl[opcode] = find_func_for (opcode);
  100.     else
  101.         cpufunctbl[opcode] = find_func_for (table68k[opcode].handler);
  102.     }
  103.     
  104. }
  105.  
  106. struct regstruct regs;
  107.  
  108. static void ShowEA(int reg, amodes mode, wordsizes size)
  109. {
  110.     UWORD dp;
  111.     BYTE disp8;
  112.     WORD disp16;
  113.     int r;
  114.     ULONG dispreg;
  115.     CPTR addr;
  116.     
  117.     switch(mode){
  118.      case Dreg:
  119.     printf("D%d", reg);
  120.     break;
  121.      case Areg:
  122.     printf("A%d", reg);
  123.     break;
  124.      case Aind:
  125.     printf("(A%d)", reg);
  126.     break;
  127.      case Aipi:
  128.     printf("(A%d)+", reg);
  129.     break;
  130.      case Apdi:
  131.     printf("-(A%d)", reg);
  132.     break;
  133.      case Ad16:
  134.     disp16 = nextiword();
  135.     addr = regs.a[reg] + (WORD)disp16;
  136.     printf("(A%d,$%04lx) == $%08lx", reg, disp16, (long unsigned int)addr);
  137.     break;
  138.      case Ad8r:
  139.     dp = nextiword();
  140.     disp8 = dp & 0xFF;
  141.     r = (dp & 0x7000) >> 12;
  142.     dispreg = dp & 0x8000 ? regs.a[r] : regs.d[r];    
  143.     if (!(dp & 0x800)) dispreg = (LONG)(WORD)(dispreg);
  144.     
  145.     addr = regs.a[reg] + disp8 + dispreg;
  146.     printf("(A%d, %c%d.%c, $%02x) == $%08lx", reg, 
  147.            dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', disp8,
  148.            (long unsigned int)addr);
  149.     break;
  150.      case PC16:
  151.     addr = m68k_getpc();
  152.     disp16 = nextiword();
  153.     addr += (WORD)disp16;
  154.     printf("(PC,$%08lx) == $%08lx", disp16, (long unsigned int)addr);
  155.     break;
  156.      case PC8r:
  157.     addr = m68k_getpc();
  158.     dp = nextiword();
  159.     disp8 = dp & 0xFF;
  160.     r = (dp & 0x7000) >> 12;
  161.     dispreg = dp & 0x8000 ? regs.a[r] : regs.d[r];
  162.     
  163.     if (!(dp & 0x800)) dispreg = (LONG)(WORD)(dispreg);
  164.     addr += disp8 + dispreg;
  165.     printf("(PC, %c%d.%c, $%02x) == $%08lx", dp & 0x8000 ? 'A' : 'D', 
  166.            (int)r, dp & 0x800 ? 'L' : 'W', disp8, (long unsigned int)addr);
  167.     break;
  168.      case absw:
  169.     printf("$%08lx", (LONG)(WORD)nextiword());
  170.     break;
  171.      case absl:
  172.     printf("$%08lx", nextilong());
  173.     break;
  174.      case imm:
  175.     switch(size){
  176.      case sz_byte:
  177.         printf("#$%02x", nextiword() & 0xff); break;
  178.      case sz_word:
  179.         printf("#$%04x", nextiword()); break;
  180.      case sz_long:
  181.         printf("#$%08lx", nextilong()); break;
  182.      default:
  183.         abort();
  184.     }
  185.     break;
  186.      case imm0:
  187.     printf("#$%02lx", nextiword() & 0xff);
  188.     break;
  189.      case imm1:
  190.     printf("#$%04lx", nextiword());
  191.     break;
  192.      case imm2:
  193.     printf("#$%08lx", nextilong());
  194.     break;
  195.      case immi:
  196.     printf("#$%04lx", reg);
  197.     break;
  198.      default:
  199.     abort();
  200.     }
  201. }
  202.  
  203. #if CPU_LEVEL > 1
  204. ULONG get_disp_ea (ULONG base, UWORD dp)
  205. {
  206.     int reg = (dp >> 12) & 7;
  207.     LONG regd;
  208.     if (dp & 0x8000)
  209.     regd = regs.a[reg];
  210.     else
  211.     regd = regs.d[reg];
  212.     if (!(dp & 0x800))
  213.     regd = (LONG)(WORD)regd;
  214.     if (dp & 0x100) {
  215.     LONG extraind = 0;
  216.     printf("020\n");
  217.     regd <<= (dp >> 9) & 3;
  218.     if (dp & 0x80)
  219.         base = 0;
  220.     if (dp & 0x40)
  221.         regd = 0;
  222.     if ((dp & 0x30) == 0x20)
  223.         base += (LONG)(WORD)nextiword();
  224.     if ((dp & 0x30) == 0x30)
  225.         base += nextilong();
  226.     
  227.     if ((dp & 0x3) == 0x2)
  228.         extraind = (LONG)(WORD)nextiword();
  229.     if ((dp & 0x3) == 0x3)
  230.         extraind = nextilong();
  231.     
  232.     if (!(dp & 4))
  233.         base += regd;
  234.     if (dp & 3)
  235.         base = get_long (base);
  236.     if (dp & 4)
  237.         base += regd;
  238.     
  239.     return base + extraind;
  240.     /* Yikes, that's complicated */
  241.     } else {
  242.     return base + (BYTE)(dp) + regd;
  243.     }
  244. }
  245. #endif
  246.  
  247. static void SuperState(void)
  248. {
  249.     if (!regs.s){
  250.     CPTR temp = regs.usp;
  251.     regs.s = 1; 
  252.     regs.t = 0;
  253.     regs.usp = regs.a[7];
  254.     regs.a[7] = temp;
  255.     }
  256. }
  257.  
  258. static void UserState(void)
  259. {
  260.     if (regs.s){
  261.     CPTR temp = regs.usp;
  262.     regs.s = 0; 
  263.     /* regs.t = 0; */
  264.     regs.usp = regs.a[7];
  265.     regs.a[7] = temp;
  266.     }
  267. }
  268.  
  269. void MakeSR(void)
  270. {
  271. #if 0
  272.     assert((regs.n & 1) == regs.n);
  273.     assert((regs.s & 1) == regs.s);
  274.     assert((regs.x & 1) == regs.x);
  275.     assert((regs.c & 1) == regs.c);
  276.     assert((regs.v & 1) == regs.v);
  277.     assert((regs.z & 1) == regs.z);
  278. #endif
  279.     regs.sr = ((regs.t << 15) | (regs.s << 13) | (regs.intmask << 8)
  280.            | (regs.x << 4) | (regs.n << 3) | (regs.z << 2) | (regs.v << 1) 
  281.            |  regs.c);
  282. }
  283.  
  284. void MakeFromSR(void)
  285. {
  286.     int olds = regs.s;
  287.  
  288.     regs.t = (regs.sr >> 15) & 1;
  289.     regs.s = (regs.sr >> 13) & 1;
  290.     regs.intmask = (regs.sr >> 8) & 7;
  291.     regs.x = (regs.sr >> 4) & 1;
  292.     regs.n = (regs.sr >> 3) & 1;
  293.     regs.z = (regs.sr >> 2) & 1;
  294.     regs.v = (regs.sr >> 1) & 1;
  295.     regs.c = regs.sr & 1;
  296.     if (olds != regs.s) {
  297.     regs.s = olds; 
  298.     if (regs.s) UserState(); else SuperState();
  299.     }
  300.     specialflags |= SPCFLAG_INT;
  301.     if (regs.t)
  302.         specialflags |= SPCFLAG_TRACE;
  303.     else
  304.         specialflags &= ~(SPCFLAG_TRACE | SPCFLAG_DOTRACE);
  305. }
  306.  
  307. void Exception(int nr)
  308. {
  309.     MakeSR();
  310.     SuperState();
  311.     if (CPU_LEVEL > 0) {
  312.     regs.a[7] -= 2;
  313.     put_word (regs.a[7], nr * 4);
  314.     }
  315.     regs.a[7] -= 4;
  316.     put_long (regs.a[7], m68k_getpc ());
  317.     regs.a[7] -= 2;
  318.     put_word (regs.a[7], regs.sr);
  319.     m68k_setpc(get_long(regs.vbr + 4*nr));
  320.     regs.t = 0;
  321.     specialflags &= ~(SPCFLAG_TRACE | SPCFLAG_DOTRACE);
  322. }
  323.  
  324. static void Interrupt(int nr)
  325. {
  326.     assert(nr < 8 && nr >= 0);
  327.     Exception(nr+24);
  328.     
  329.     regs.intmask = nr;
  330.     specialflags |= SPCFLAG_INT;
  331. }
  332.  
  333. static int caar, cacr;
  334.  
  335. void m68k_move2c (int regno, ULONG *regp)
  336. {
  337.     if (CPU_LEVEL == 1 && (regno & 0x7FF) > 1)
  338.     op_illg (0x4E7B);
  339.     else
  340.     switch (regno) {
  341.      case 0: regs.sfc = *regp; break;
  342.      case 1: regs.dfc = *regp; break;
  343.      case 2: cacr = *regp & 0xFF; break;
  344.      case 0x800: regs.usp = *regp; break;
  345.      case 0x801: regs.vbr = *regp; break;
  346.      case 0x802: caar = *regp & 0xFF; break;
  347.      default:
  348.         op_illg (0x4E7B);
  349.         break;
  350.     }
  351. }
  352.  
  353. void m68k_movec2 (int regno, ULONG *regp)
  354. {
  355.     if (CPU_LEVEL == 1 && (regno & 0x7FF) > 1)
  356.     op_illg (0x4E7A);
  357.     else
  358.     switch (regno) {
  359.      case 0: *regp = regs.sfc; break;
  360.      case 1: *regp = regs.dfc; break;
  361.      case 2: *regp = cacr; break;
  362.      case 0x800: *regp = regs.usp; break;
  363.      case 0x801: *regp = regs.vbr; break;
  364.      case 0x802: *regp = caar; break;
  365.      default:
  366.         op_illg (0x4E7A);
  367.         break;
  368.     }
  369. }
  370.  
  371. extern void m68k_divl (UWORD opcode, ULONG src, UWORD extra)
  372. {
  373.     if (src == 0)
  374.     return;
  375. #ifdef INT_64BIT
  376.     if (extra & 0x800) {
  377.     /* signed variant */
  378.     INT_64BIT a = regs.d[(extra >> 12) & 7];
  379.     INT_64BIT quot, rem;
  380.     
  381.     if (extra & 0x400)
  382.         a |= (INT_64BIT)regs.d[extra & 7] << 32;
  383.     rem = a % src;
  384.     quot = a / src;
  385.     if ((extra & 0x400) && (extra & 7) != ((extra >> 12) & 7))
  386.         regs.d[extra & 7] = rem;
  387.     regs.d[(extra >> 12) & 7] = quot;
  388.     } else {
  389.     /* unsigned */
  390.     unsigned INT_64BIT a = regs.d[(extra >> 12) & 7];
  391.     unsigned INT_64BIT quot, rem;
  392.     
  393.     if (extra & 0x400)
  394.         a |= (INT_64BIT)regs.d[extra & 7] << 32;
  395.     rem = a % src;
  396.     quot = a / src;
  397.     if ((extra & 0x400) && (extra & 7) != ((extra >> 12) & 7))
  398.         regs.d[extra & 7] = rem;
  399.     regs.d[(extra >> 12) & 7] = quot;
  400.     }
  401. #endif
  402. }
  403.  
  404. extern void m68k_mull (UWORD opcode, ULONG src, UWORD extra)
  405. {
  406. #ifdef INT_64BIT
  407.     if (extra & 0x800) {
  408.     /* signed variant */
  409.     INT_64BIT a = (LONG)regs.d[(extra >> 12) & 7];
  410.  
  411.     a *= (LONG)src;
  412.     if ((extra & 0x400) && (extra & 7) != ((extra >> 12) & 7))
  413.         regs.d[extra & 7] = a >> 32;
  414.     regs.d[(extra >> 12) & 7] = (ULONG)a;
  415.     } else {
  416.     /* unsigned */
  417.     unsigned INT_64BIT a = (ULONG)regs.d[(extra >> 12) & 7];
  418.     unsigned INT_64BIT quot, rem;
  419.     
  420.     a *= src;
  421.     if ((extra & 0x400) && (extra & 7) != ((extra >> 12) & 7))
  422.         regs.d[extra & 7] = a >> 32;
  423.     regs.d[(extra >> 12) & 7] = (ULONG)a;
  424.     }
  425. #endif
  426. }
  427.  
  428. static char* ccnames[] =
  429. { "T ","F ","HI","LS","CC","CS","NE","EQ",
  430.   "VC","VS","PL","MI","GE","LT","GT","LE" };
  431.  
  432. void MC68000_reset(void)
  433. {
  434.     regs.a[7] = get_long(0x00f80000);
  435.     m68k_setpc(get_long(0x00f80004));
  436.     regs.s = 1;
  437.     regs.stopped = 0;
  438.     regs.t = 0;
  439.     specialflags = 0;
  440.     regs.intmask = 7;
  441.     regs.vbr = regs.sfc = regs.dfc = 0;
  442.     customreset();
  443. }
  444.  
  445. void op_illg(UWORD opcode)
  446. {
  447.     if (opcode == 0xF00D && ((m68k_getpc() & 0xF80000) == 0xF80000)) {
  448.     /* This is from the dummy Kickstart replacement */
  449.     ersatz_perform (nextiword ());
  450.     return;
  451.     }
  452.     regs.pc_p--;
  453.     if ((opcode & 0xF000) == 0xF000) {
  454.     if ((opcode & 0xE00) == 0x200)
  455.         Exception(0xB);
  456.     else 
  457.         switch (opcode & 0x1FF) {
  458.          case 0x17:
  459.         regs.pc_p+=2;
  460.         break;
  461.          default:
  462.         regs.pc_p++;
  463.         }
  464.     return;
  465.     }
  466.     if ((opcode & 0xF000) == 0xA000) {
  467.         Exception(0xA);
  468.     return;
  469.     }
  470.     fprintf(stderr, "Illegal instruction: %04x\n", opcode);
  471.     Exception(4);
  472. }
  473.  
  474. static int n_insns=0, n_spcinsns=0;
  475.  
  476. static __inline__ void do_hardware(void)
  477. {
  478.     if (specialflags & SPCFLAG_BLIT) {
  479.     do_blitter();
  480. #ifdef NO_FAST_BLITTER
  481.     do_blitter();
  482.     do_blitter();
  483.     do_blitter();
  484. #endif
  485.     }
  486.     if (specialflags & SPCFLAG_DISK) {
  487.     do_disk(); /* This is not critical. Four calls make disk */
  488.     do_disk(); /* loading quite fast. */
  489.     do_disk();
  490.     do_disk();
  491.     }
  492. }
  493.  
  494. void MC68000_run(void)
  495. {
  496.     for(;;) {
  497.     UWORD opcode;
  498.     /* assert (!regs.stopped && !(specialflags & SPCFLAG_STOP)); */
  499.     opcode = nextiword();
  500. #ifdef COUNT_INSTRS
  501.     instrcount[opcode]++;
  502. #endif
  503.     (*cpufunctbl[opcode])(opcode);
  504. #ifndef NO_EXCEPTION_3
  505.     if (buserr) {
  506.         Exception(3);
  507.         buserr = false;
  508.     }
  509. #endif
  510.     /*n_insns++;*/
  511.     do_cycles();    
  512.     if (specialflags) {
  513.         /*n_spcinsns++;*/
  514.         while (specialflags & SPCFLAG_STOP) {
  515.         do_cycles();
  516.         do_hardware();
  517.         if (specialflags & (SPCFLAG_INT | SPCFLAG_DOINT)){
  518.             int intr = intlev();
  519.             specialflags &= ~(SPCFLAG_INT | SPCFLAG_DOINT);
  520.             specialflags &= ~(SPCFLAG_INT | SPCFLAG_DOINT);
  521.             if (intr != -1 && intr > regs.intmask) {
  522.             Interrupt(intr);
  523.             regs.stopped = 0;
  524.             specialflags &= ~SPCFLAG_STOP;
  525.             }        
  526.         }        
  527.         }
  528.         if (specialflags & SPCFLAG_DOTRACE) {
  529.         Exception(9);
  530.         }
  531.         if (specialflags & SPCFLAG_TRACE) {
  532.         specialflags &= ~SPCFLAG_TRACE;
  533.         specialflags |= SPCFLAG_DOTRACE;
  534.         }
  535. #ifdef WANT_SLOW_MULTIPLY
  536.         /* Kludge for Hardwired demo. The guys who wrote it should be
  537.          * mutilated. */
  538.         if (specialflags & SPCFLAG_EXTRA_CYCLES) {
  539.         do_cycles ();
  540.         do_cycles ();
  541.         do_cycles ();
  542.         do_cycles ();
  543.         specialflags &= ~SPCFLAG_EXTRA_CYCLES;
  544.         }
  545. #endif
  546.         do_hardware();
  547.         
  548.         if (specialflags & SPCFLAG_DOINT) {
  549.         int intr = intlev();
  550.         specialflags &= ~(SPCFLAG_INT | SPCFLAG_DOINT);
  551.         if (intr != -1 && intr > regs.intmask) {
  552.             Interrupt(intr);
  553.             regs.stopped = 0;
  554.         }        
  555.         }
  556.         if (specialflags & SPCFLAG_INT) {
  557.         specialflags &= ~SPCFLAG_INT;
  558.         specialflags |= SPCFLAG_DOINT;
  559.         }
  560.         if (specialflags & SPCFLAG_BRK) {        
  561.         specialflags &= ~SPCFLAG_BRK;
  562.         return;        
  563.         }
  564.     }
  565.     }
  566. }
  567.  
  568. void MC68000_step(void)
  569. {
  570.     specialflags |= SPCFLAG_BRK;
  571.     MC68000_run();
  572. }
  573.  
  574. void MC68000_skip(CPTR nextpc)
  575. {
  576.     broken_in = false;
  577.     specialflags |= SPCFLAG_BRK;
  578.     do {
  579.     MC68000_step();
  580.     } while (nextpc != m68k_getpc() && !broken_in);
  581. }
  582.  
  583. void MC68000_disasm(CPTR addr, CPTR *nextpc, int cnt)
  584. {
  585.     CPTR pc = m68k_getpc();
  586.     m68k_setpc(addr);
  587.     for (;cnt--;){
  588.     char instrname[20],*ccpt;
  589.     int opwords;
  590.     UWORD opcode;
  591.     UWORD special = 0;
  592.     struct mnemolookup *lookup;
  593.     struct instr *dp;
  594.     printf("%08lx: ", m68k_getpc());
  595.     for(opwords = 0; opwords < 5; opwords++){
  596.         printf("%04x ", get_word(m68k_getpc() + opwords*2));
  597.     }
  598.     
  599.     opcode = nextiword();
  600.     if (cpufunctbl[opcode] == op_illg) {
  601.         opcode = 0x4AFC;
  602.     }
  603.     dp = table68k + opcode;
  604.     for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++)
  605.         ;
  606.     
  607.     strcpy(instrname,lookup->name);
  608.     ccpt = strstr(instrname,"cc");
  609.     if (ccpt != 0) {
  610.         strncpy(ccpt,ccnames[dp->cc],2);
  611.     }
  612.     printf("%s", instrname);
  613.     switch(dp->size){
  614.      case sz_byte: printf(".B "); break;
  615.      case sz_word: printf(".W "); break;
  616.      case sz_long: printf(".L "); break;
  617.      default: break;
  618.     }
  619.  
  620.     if (dp->suse) {
  621.         ShowEA(dp->sreg, dp->smode, dp->size);
  622.     }
  623.     if (dp->suse && dp->duse)
  624.         printf(",");
  625.     if (dp->duse) {
  626.         ShowEA(dp->dreg, dp->dmode, dp->size);
  627.     }
  628.     if (ccpt != 0) {
  629.         if (cctrue(dp->cc))
  630.         printf(" (TRUE)");
  631.         else 
  632.         printf(" (FALSE)");
  633.     }
  634.     printf("\n");
  635.     }
  636.     *nextpc = m68k_getpc();
  637.     m68k_setpc(pc);
  638. }
  639.  
  640. void MC68000_dumpstate(CPTR *nextpc)
  641. {
  642.     int i;
  643.     for(i = 0; i < 8; i++){
  644.     printf("D%d: %08lx ", i, regs.d[i]);
  645.     if ((i & 3) == 3) printf("\n");
  646.     }
  647.     for(i=0;i<8;i++){
  648.     printf("A%d: %08lx ", i, regs.a[i]);
  649.     if ((i & 3) == 3) printf("\n");
  650.     }
  651.     printf ("T=%d S=%d X=%d N=%d Z=%d V=%d C=%d IMASK=%d\n", regs.t, regs.s, 
  652.         regs.x, regs.n, regs.z, regs.v, regs.c, regs.intmask);
  653.     MC68000_disasm(m68k_getpc(), nextpc, 1);
  654.     printf("next PC: %08lx\n", *nextpc);
  655. }
  656.  
  657.